package task

import (
	"encoding/base64"
	"encoding/json"
	"fmt"
	"github.com/xuelang-group/sh-solver-scheduler/internal/infra"
	"strconv"
	"strings"

	"github.com/sirupsen/logrus"
	"github.com/xuelang-group/sh-solver-scheduler/internal/domain/entity"
	"github.com/xuelang-group/sh-solver-scheduler/pkg/options"
	"github.com/xuelang-group/sh-solver-scheduler/pkg/utils"
	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// 求解器 service
func GetSolverTaskPod(task *entity.SolverTask) (*corev1.Pod, error) {
	container, err := getSolverContainer(task)
	if err != nil {
		return nil, err
	}

	labels := GetDefaultLabels(task.ID)

	pod := corev1.Pod{
		ObjectMeta: metav1.ObjectMeta{
			Name:      strconv.Itoa(task.ID),
			Namespace: task.Namespace,
			Labels:    labels,
		},

		Spec: corev1.PodSpec{
			RestartPolicy: corev1.RestartPolicyNever,
			Containers:    []corev1.Container{*container},
		},
	}

	return &pod, nil
}

func getSolverContainer(task *entity.SolverTask) (*corev1.Container, error) {
	container := corev1.Container{
		Name: "solver",
		// TODO:
		Image: task.SolverSpec.Image,
		Command: utils.BashRunCommand(getSolverTaskCommand(options.SolverTaskContext{
			UserId:       "user123",
			AppId:        strconv.Itoa(task.ID),
			NodeId:       strconv.Itoa(task.ID),
			RunType:      "batch",
			Cmd:          getCmdStr(task),
			DownloadList: getDownloadList(task.DownloadList),
			UploadList:   getUploadList(task.UploadList),
		})),
		ImagePullPolicy: corev1.PullPolicy("IfNotPresent"),
		Env:             getEnvList(task),
		Ports:           []corev1.ContainerPort{},
		SecurityContext: &corev1.SecurityContext{
			Privileged: boolPtr(true),
		},
	}

	return &container, nil
}

func boolPtr(b bool) *bool { return &b }

func getDownloadList(v []entity.DownloadListItem) []options.DownloadList {
	dlist := make([]options.DownloadList, 0)
	for _, v := range v {
		isDir := false
		if v.IsDir == "true" { //TODO: true or false str
			isDir = true
		}
		dlist = append(dlist, options.DownloadList{
			OssPath:   v.OssPath,
			IsDir:     isDir,
			LocalPath: v.LocalPath,
		})
	}

	return dlist
}

func getUploadList(v []entity.UploadListItem) []options.UploadList {
	wlist := make([]options.UploadList, 0)
	for _, v := range v {
		wlist = append(wlist, options.UploadList{
			IsDir:     true,
			OssPath:   v.OssPath,
			LocalPath: v.LocalPath,
		})
	}

	return wlist
}

func getEnvList(_ *entity.SolverTask) []corev1.EnvVar {
	envList := make([]corev1.EnvVar, 0)
	envList = append(envList, []corev1.EnvVar{
		{
			Name:  "SH_SOLVER_SERVICE_ENDPOINT",
			Value: "http://solver-scheduler-service.sh-dc:9000",
		},
		{
			Name:  "OSS_TYPE",
			Value: infra.GetConfig().OSS.Type, // "minio",
		},
		{
			Name:  "OSS_ENDPOINT",
			Value: infra.GetConfig().OSS.Endpoint, //"http://10.13.13.182:30002", // "https://oss-cn-hangzhou.aliyuncs.com/",
		},
		{
			Name:  "OSS_BUCKET",
			Value: infra.GetConfig().OSS.Bucket, //"sh-dc", // "xuelang5t",
		},
		{
			Name:  "OSS_ACCESS_KEY",
			Value: infra.GetConfig().OSS.AccessKey, //"Minio@admin", // "LTAI5tR44wiAkfcaRV2KG8Zg",
		},
		{
			Name:  "OSS_ACCESS_SECRET",
			Value: infra.GetConfig().OSS.AccessSecret, //"rX6sW5zJ6kX8", // "95xbj1QmqQZJsxGscaSZ9ip6TbiP3U",
		},
	}...)

	// 填充求解器原生定义的env
	// for _, env := range task.SolverSpec.EnvList {
	// 	envList = append(envList, corev1.EnvVar{
	// 		Name:  env.Name,
	// 		Value: env.Value,
	// 	})
	// }
	return envList
}

// export PATH=/home/DLUTFem/LinuxArtifacts/bin:$PATH;
// export LD_LIBRARY_PATH=/home/DLUTFem/LinuxArtifacts/lib:$LD_LIBRARY_PATH;
// DLUTFem -i /home/DLUTFem/LinuxArtifacts/case/Whole_shell_4in1.bdf -w result -j result
func getCmdStr(task *entity.SolverTask) string {
	exportStr := ""
	// 求解器定义原生env
	// for _, env := range task.SolverSpec.EnvList {
	// 	exportStr += "export " + env.Name + "=" + env.Value + ";"
	// }
	// 用户可能会修改
	for _, env := range task.Envs {
		exportStr += "export " + env.Name + "=" + env.Value + ";"
	}

	optionStr := ""
	for _, option := range task.Options {
		if strings.Contains(task.SolverSpec.Cmd, "{{"+option.OptionKey+"}}") {
			task.SolverSpec.Cmd = strings.Replace(task.SolverSpec.Cmd, "{{"+option.OptionKey+"}}", option.OptionKey+" "+option.OptionValue, 1)
		} else {
			optionStr += " " + option.OptionKey + " " + option.OptionValue
		}
	}

	return exportStr + task.SolverSpec.Cmd + optionStr
}

func getSolverTaskCommand(context options.SolverTaskContext) string {
	logrus.Infof("context: %+v", context)
	b, _ := json.Marshal(context)
	contextEnc := base64.StdEncoding.EncodeToString(b)
	// http://10.13.13.182:30002/sh-dc/connectgo
	return fmt.Sprintf(`curl '%s' -o /tmp/connect && chmod +x /tmp/connect && spentry=sh exec /tmp/connect %s`, infra.GetConfig().Connect.URL, contextEnc)
}

func getSolverTaskName(name string) string {
	return base64.StdEncoding.EncodeToString([]byte(name)) + "-" + utils.RandStr(8)
}
